format PE console 4.0

include 'E:/bin/fasm/include/win32ax.inc'
include 'E:/bin/fasm/include/api/kernel32.inc'
include 'E:/bin/fasm/include/api/user32.inc'
include 'E:/bin/fasm/include/api/shell32.inc'

entry _main

section '.text' code readable executable
use32

_main:

	call	get_command_line_args

	call	load_source_file

	call	alloc_dst_buff

	call	assemble

	;call	 write_destination_file


	;invoke  MessageBox, 0, [dst_hwnd], 0,0

_exit:
	cinvoke system,"pause"
	cinvoke exit,0
	ret


alloc_dst_buff:
	invoke	VirtualAlloc,0,[dst_buff_size],MEM_COMMIT,PAGE_READWRITE
	test	eax,eax
	jz	_exit
	mov	[dst_ptr],eax
	ret


; Loads the source file (asm code input)
; out ( [src_path] )
; change ( eax, ebx, ecx )
load_source_file:
	cmp	byte[src_path],0
	je	_exit

	invoke	CreateFile,src_path,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
	cmp	eax,INVALID_HANDLE_VALUE
	je	_exit

	push	eax			; store file handle
	invoke	GetFileSize,eax,0
	push	eax			; store file size
	invoke	VirtualAlloc,0,eax,MEM_COMMIT,PAGE_READWRITE;+MEM_RESERVE
	test	eax,eax
	jz	_exit
	mov	[src_ptr],eax

	pop	ebx    ; size
	pop	ecx    ; file hwnd
	push	ecx
	push	ebx

	invoke	ReadFile,ecx,eax,ebx,useless,0
	test	eax,eax
	jz	_exit

	pop	ebx

; + --- BEGIN: Add special characters in the end of file

	mov	edi,[src_ptr]
	mov	word[edi+ebx],(C_EOF shl 8) + C_NEWLINE

; + ---- END

	pop	eax
	invoke	CloseHandle,eax
	ret


; Saves the binary file
write_destination_file:
	mov	esi,src_path
    @@: inc	esi
	cmp	byte[esi],0
	jnz	@b
	mov	dword[esi-3],'bin'

	invoke	CreateFile,src_path,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0
	cmp	eax,INVALID_HANDLE_VALUE
	je	exit
	push	eax
	invoke	WriteFile,eax,[dst_ptr],[dst_total_bytes_to_write],useless,0
	test	eax,eax
	jz	_exit
	pop	eax
	invoke	CloseHandle,eax
	ret


; Get command line args, in the format:
;     <app_path> <src_file_path> [<parameters>]
;     zasm.exe example.asm -output myapp.exe
; change (app_path, src_path)
get_command_line_args:
	invoke	GetCommandLine
	mov	esi,eax
	mov	edi,app_path
	call	.storePath
	mov	edi,src_path
	call	.storePath
	; TODO: read parameters
	jmp	.done
    .storePath:
	cmp	byte[esi],'"'
	je	.quotedPath
    @@: movsb
	cmp	byte[esi],0
	je	.done
	cmp	byte[esi],' '
	jne	@b
	inc	esi ; skip <space>
	ret
    .quotedPath:
	inc	esi ; skip <open ">
    @@: movsb
	cmp	byte[esi],'"'
	jne	@b
	inc	esi ; skip <close ">
	inc	esi ; skip <space>
 .done: ret


; +---------------------------------------------------------------------------


macro savebyte
{
	stosb
	inc	[dst_total_bytes_to_write]
}



assemble:	xor	eax,eax
		mov	esi,[src_ptr]
		;mov	 edi,[dst_ptr]
		call	bnf_code
		jne	invalidLine
		ret
invalidLine:
		mov	eax,str_line
		call	invalid
il:
		mov eax,str_number
		call invalid


bnf_code:	call	bnf_skipspace_m
		mov	ebp,esi
		lodsb
		cmp	al,'@'
		jne	.yes
		call	bnf_capname_s
		jne	.yes
		mov	ebx,HEADERS
		mov	ecx,HEADERS.size
		call	array_search
		jne	.yes
		call	dword[ebx]	  ; bnf_operand_xxxx
		jne	.no2
		ret
	  .yes: mov	esi,ebp
		call	bnf_body
	   .no: ret
	  .no2: mov	esi,ebp
		ret
; <code> = @PE <PE> | @PEC <PE> | @DLL <PE> | @COM <body> | @BIN <body> | <body>
; change (all)
; return (ZF) 1 = is code


bnf_pe: 	call	bnf_skipspace_m
		lodsb
		cmp	al,'@'
		jne	.no
		call	bnf_lowname_s
		jne	.no
		mov	ebx,SESSIONS
		mov	ecx,SESSIONS.size
		call	array_search
		jne	.no
		call	dword[ebx]   ;
		jne	bnf_pe
	   .no: ret
; <PE> = <session_code> <session_data> <session_bss> <session_idata>
; change (all)
; return (ZF) 1 = is code


bnf_pe_session: call	bnf_access_flag
		call	bnf_endline
		jne	.no
		call	bnf_body
	   .no: ret
; <access_flag> <newline> <body>
; change (all)
; return (ZF) 1 = is PE session


bnf_body:	call	bnf_statement
		jne	.no
		cmp	byte[esi],C_EOF
		jne	bnf_body
	   .no: ret
; <body> = <statement>*
; change (edi, ecx, ebx, edx, ebp)
; return (ZF) 1 = is body


bnf_block:	call	bnf_skipspace
		lodsb
		cmp	al,'{'
		jne	.no
		call	bnf_body
		lodsb
		cmp	al,'}'
		je     .yes
	   .no: dec    esi
	  .yes: ret
; <block> = '{' <body> '}'
; change (edi, ecx, ebx, edx, ebp)
; return (ZF) 1 = is block


bnf_statement:	call	bnf_label
		je	bnf_statement
		call	bnf_command
		call	bnf_comment
		call	bnf_endline
		ret
; <statement> = <label>* <command>? <comment>? <endline>
; change (edi, ecx, ebx, edx, ebp)
; return (ZF) 1 = is statement


bnf_mem:	mov	edi,esi
		call	bnf_op_override
		lodsb
		cmp	al,'['
		jne	.no
		call	bnf_mem_displacement
		jne	.no
		lodsb
		cmp	al,']'
		jne	.no
		xor	eax,eax
		ret
	   .no: mov	esi,edi
		ret
; <mem> = <op_override>? '[' (<m32> | <m16> | <m08>) ']'
; return (ZF) 1 = is memory operand


bnf_mem_displacement:
		call	bnf_imm
		ret


bnf_reg:	mov	edi,esi
		call	bnf_lowname_s
		jne	.no
		mov	ebx,reg_list
		mov	ecx,reg_list.size
		call	array_search2
		je	.yes
	   .no: mov	esi,edi
	  .yes: ret
; <reg> = <r32> | <r16> | <r08>
; change ( edx, ecx )


bnf_struct:	call	bnf_skipspace
		mov	ebp,esi
		lodsb
		cmp	al,'{'
		jne	.yes
	  .nxt: call	bnf_number
		jne	@f
		lodsb
		cmp	al,'.'
		jne	.no
		jmp	.k3
	    @@: cmp	al,'.'
		je	.no
	   .k3: call	bnf_name
		jne	.k
		lodsb
		cmp	al,'.'
		jne	@f
		call	bnf_op_override
		jne	.no
		jmp	.k
	    @@: dec	esi
	    .k: lodsb
		cmp	al,'='
		jne	@f
		call	bnf_number
		jne	.no
		jmp	.k2
	    @@: dec	esi
	   .k2: lodsb
		cmp	al,C_NEWLINE
		je	.no
		cmp	al,'}'
		jne	.nxt
		je	.yes2
	   .no: mov	esi,ebp
	 .yes2: ret
	  .yes: mov	esi,ebp
		xor	eax,eax
		ret
; <struct> = '{' ( <s> (<number>.)? <name> (.<op_override>)? (=<number>)? )* '}'
; change (ebp, ebx)
; return (ZF) 1 = is struct


bnf_operand_dst_src:
		call	bnf_skipspace
		call	bnf_mem
		je	.isMem
		call	bnf_reg
		jne	.notDstSrc
		mov	ebx,bnf_operand_src
		jmp	@f
	.isMem: mov	ebx,bnf_operand_srci
	    @@: call	ebx
    .notDstSrc: ret
; <bnf_operand_dst_src> = <reg> <s> <operand_src> | <mem> <s> <operand_srci>
; change ( ebx, edx, ecx )
; return (ZF) 1 = is dst and src operands


bnf_operand_none:
		xor	eax,eax
		ret


bnf_operand_imm:call	bnf_skipspace
		call	bnf_imm
		ret
; return (ZF) 1 = is immediate operand


bnf_operand_str:call	bnf_skipspace
		call	bnf_string
		ret
; return (ZF) 1 = is string operand


bnf_operand_dirsize:
		call	bnf_skipspace
		call	bnf_string
		call	bnf_block
		ret
; return (ZF) 1 = is directive size operand


bnf_operand_dst:call	bnf_skipspace
		call	bnf_mem
		je	.yes
		call	bnf_reg
	  .yes: ret
; <operand_dst> = <reg> | <mem>
; change (edx, ecx)
; return (ZF) 1 = is dst operand


bnf_operand_src:call	bnf_skipspace
		call	bnf_mem
		je	.yes
		call	bnf_reg
		je	.yes
		call	bnf_imm
	  .yes: ret
; <operand_src> = <reg> | <mem> | <imm>
; change (edx, ecx, ebx)
; return (ZF) 1 = is src operand


bnf_operand_srci:
		call	bnf_skipspace
		call	bnf_reg
		je	.yes
		call	bnf_imm
	  .yes: ret
; <bnf_operand_srci> = <reg> | <imm>
; change (edx, ecx, ebx)
; return (ZF) 1 = is src


bnf_operand_def_data:
	    @@: call	bnf_is_space
		jne	.yes
		call	bnf_skipspace
		lodsb
		cmp	al,'?'
		je	@b
		dec	esi
		call	bnf_imm
		je	@b
	  .yes: xor	eax,eax
		ret
; <def_data> = d<op_override> ( (<s> '?')? | (<s> ('?' | <imm>))+ )
; change (ebx)


bnf_operand_def_rdata:
		call	bnf_skipspace
		call	bnf_imm
		jne	.no
		call	bnf_struct
	   .no: ret
; <operand_def_rdata> = <imm> <struct>?


bnf_command:	call	bnf_skipspace
		call	bnf_directive
		je	.yes
		;call	 bnf_macro
		;je	 .yes
		call	bnf_constant
		je	.yes
		call	bnf_instruction
	  .yes: ret
; <command> = <macro> | <directive> | <instruction> | <constant>
; change (edi, ecx, ebx, edx, ebp)
; return (ZF) 1 = is command


bnf_constant:	mov	ebp,esi
		call	bnf_capname_s
		jne	.no
		call	bnf_is_space
		jne	.no
		call	bnf_skipspace
		call	bnf_imm
		jne	.no
		ret
	   .no: mov	esi,ebp
		ret
; <constant> = <capname> <s> <imm>
; change (ebx, ebp, ecx, edi)
; return (ZF) 1 = is constant


bnf_directive:	mov	ebp,edi
		lodsb
		cmp	al,'@'
		jne	.no
		call	bnf_lowname_or_num_s
		jne	.no
		mov	ebx,DIRECTIVES
		mov	ecx,DIRECTIVES.size
		call	array_search
		jne	.no
		call	dword[ebx]
		je	.yes
	   .no: mov	esi,ebp
	  .yes: ret
; <directive>  = @(<dir_debug> | <dir_release> | <dir_include> | <dir_size> | <dir_16bit> | <dir_32bit> | <dir_org> | <dir_align>)


bnf_instruction:mov	edi,esi
		call	bnf_lowname_s
		jne	.no
		mov	ebx,INSTS
		mov	ecx,INSTS.size
		call	array_search
		jne	.no
		mov	ebp,edi
		call	dword[ebx]     ; call bnf_operand_xxxxxx
		je     .yes
		mov	esi,ebp
	  .yes: ret
	   .no: mov	esi,edi
		ret
; <instruction> = <add> | <mov> | <inc> | ...
; change (edi, ecx, ebx, edx, ebp)
; return (ZF) 1 = is instruction


bnf_comment:	call	bnf_skipspace
		lodsb
		cmp	al,';'
		jne	.no
		lodsb
		cmp	al,'*'
		jne	.single
		call	bnf_comment_blocks
		ret
       .single: dec	esi
		call	bnf_anything  ; [see bnf_comment_single]
	  .yes: ret
	   .no: dec	esi
		ret
; <comment> = ; (<comment_single> | <comment_blocks>)
; change (edi)
; return (ZF) 1 = is comment


bnf_comment_single:
		call	bnf_anything_l
		ret
; <comment_single> = <anything> <endline>


bnf_comment_blocks:
		mov	ah,'*'
		call	bnf_anything_m
		lodsb
		cmp	al,';'
		je	.yes
		dec	esi
	  .yes: ret
; <comment_blocks> = '*' <anything> '*;'


bnf_imm:	mov	ecx,esi
		call	bnf_expression
		je	@f
		mov	esi,ecx
	    @@: ret
; <expression> = <imm>
; change (ebx, edi, ecx)
; return (ZF) 1 = is immediate value


bnf_expression: call	bnf_signed_term
		jne	.no
	    @@: call	bnf_addop
		jne	.ok
		call	bnf_signed_term
		je	@b
		ret
	   .ok: xor	eax,eax
	   .no: ret
; <expression> = <signed_term> (<addop> <signed_term>)*
; change (ebx, edi, ecx)
; return (ZF) 1 = is expression


bnf_signed_term:call	bnf_addop
		call	bnf_term
		ret
; <signed_term> = <addop>? <term>
; change ( ebx )
; return (ZF) 1 = is signed term


bnf_term:	call	bnf_factor
		jne	.no
		call	bnf_mulop
		jne	.ok
		call	bnf_signed_term
		ret
	   .ok: xor	eax,eax
	   .no: ret
; <term> = <factor> (<mulop> <signed_term>)*
; change (ebx, edi)
; return (ZF) 1 = is term


bnf_factor:	lodsb
		cmp	al,'('
		je	@f
		dec	esi
		push	esi
		call	bnf_id
		pop	ebx
		cmp	ebx,esi
		jz	.no
		xor	eax,eax
		ret
	    @@: push	esi
		call	bnf_expression
		pop	ebx
		cmp	ebx,esi
		jz	.no
		lodsb
		cmp	al,')'
		jne	.no
		ret
	   .no: dec	esi
		ret
; <factor> = <imm> | '(' <expression> ')'
; change (ebx, edi)
; return (ZF) 1 = is factor


bnf_id: 	call	bnf_string
		je	.yes
		call	bnf_label_op
		je	.yes
		call	bnf_number
	  .yes: ret
; <imm> = <label> | <string> | <number>
; change (ebx, edi)
; return (ZF) 1 = is immediate


bnf_mulop:	lodsb
		cmp	al,'*'
		je	.yes
		cmp	al,'/'
		je	.yes
		cmp	al,'%'
		je	.yes
		dec	esi
	  .yes: ret
; <mulop> = * | / | %
; return (ZF) 1 = is mulop


bnf_addop:	lodsb
		cmp	al,'+'
		je	.yes
		cmp	al,'-'
		je	.yes
		dec	esi
	  .yes: ret
; <addop> = + | -
; return (ZF) 1 = is addop


bnf_label_global:
bnf_name:	lodsb
		cmp	al,'a'
		jb	.no
		cmp	al,'z'
		ja	.no
		mov	ebx,keyword
		mov	[ebx],al
	    @@: lodsb
		inc	ebx
		mov	[ebx],al
		cmp	al,'_'
		je	@b
		cmp	al,'0'
		jb	.done
		cmp	al,'9'
		jbe	@b
		cmp	al,'A'
		jb	.done
		cmp	al,'Z'
		jbe	@b
		cmp	al,'a'
		jb	.done
		cmp	al,'z'
		jbe	@b
	 .done: dec	esi
		xor	eax,eax
		mov	[ebx],al
		ret
	   .no: dec	esi
		ret
; <name> = [a-z][a-zA-Z0-9_]*
; return (ZF) 1 = is name


bnf_lowname:	mov	edi,esi
		lodsb
		cmp	al,'a'
		jb	.no
		cmp	al,'z'
		ja	.no
	    @@: lodsb
		cmp	al,'_'
		je	@b
		cmp	al,'a'
		jb	.done
		cmp	al,'z'
		jbe	@b
	 .done: sub	al,'A'
		cmp	al,'Z' - 'A' + 1
		jbe	.no
		dec	esi
		xor	eax,eax
		ret
	   .no: mov	esi,edi
		ret
; <lowname>  = [a-z][a-z]*
; change (edi)
; return (ZF) 1 = is lowername
bnf_lowname_s:	mov	edi,esi
		lodsb
		cmp	al,'a'
		jb	.no
		cmp	al,'z'
		ja	.no
		mov	ebx,keyword
		mov	[ebx],al
	    @@: lodsb
		inc	ebx
		mov	[ebx],al
		cmp	al,'_'
		je	@b
		cmp	al,'a'
		jb	.done
		cmp	al,'z'
		jbe	@b
	 .done: sub	al,'A'
		cmp	al,'Z' - 'A' + 1
		jbe	.no
		dec	esi
		xor	eax,eax
		mov	byte[ebx],al
		ret
	   .no: mov	esi,edi
		ret
; same as bnf_lowname, but store the string result in keyword
bnf_lowname_or_num_s:
		mov	edi,esi
		lodsb
		cmp	al,'0'
		jb	.no
		cmp	al,'9'
		jbe	@f
		cmp	al,'a'
		jb	.no
		cmp	al,'z'
		ja	.no
	    @@: mov	ebx,keyword
		mov	[ebx],al
	    @@: lodsb
		inc	ebx
		mov	[ebx],al
		cmp	al,'0'
		jb	.done
		cmp	al,'9'
		jbe	@b
		cmp	al,'a'
		jb	.done
		cmp	al,'z'
		jbe	@b
	 .done: sub	al,'A'
		cmp	al,'Z' - 'A' + 1
		jbe	.no
		dec	esi
		xor	eax,eax
		mov	byte[ebx],al
		ret
	   .no: mov	esi,edi
		ret
; <lowname_or_num> = [a-z0-9][a-z0-9]*
; change (edi, ebx)
; return (ZF) 1 = is lowername or number string; store the string result in keyword


bnf_constant_op:
bnf_capname:	mov	edi,esi
		lodsb
		cmp	al,'A'
		jb	.no
		cmp	al,'Z'
		ja	.no
	    @@: lodsb
		cmp	al,'_'
		je	@b
		cmp	al,'0'
		jb	.done
		cmp	al,'9'
		jbe	@b
		cmp	al,'A'
		jb	.done
		cmp	al,'Z'
		jbe	@b
	 .done: sub	al,'a'
		cmp	al,'z' - 'a' + 1
		jbe	.no
		dec	esi
		xor	eax,eax
		ret
	   .no: mov	esi,edi
		ret
; <capname> = [A-Z][A-Z0-9_]*
; change (edi, ebx)
; return (ZF) 1 = is uppername string
bnf_capname_s:	mov	edi,esi
		lodsb
		cmp	al,'A'
		jb	.no
		cmp	al,'Z'
		ja	.no
		mov	ebx,keyword
		mov	[ebx],al
	    @@: lodsb
		inc	ebx
		mov	[ebx],al
		cmp	al,'_'
		je	@b
		cmp	al,'0'
		jb	.done
		cmp	al,'9'
		jbe	@b
		cmp	al,'A'
		jb	.done
		cmp	al,'Z'
		jbe	@b
	 .done: sub	al,'a'
		cmp	al,'z' - 'a' + 1
		jbe	.no
		dec	esi
		xor	eax,eax
		mov	byte[ebx],al
		ret
	   .no: mov	esi,edi
		ret
; same as bnf_capname, but store the string result in keyword


bnf_label:	call	bnf_skipspace
		call	bnf_label_ref_once
		je	.ok
		call	bnf_label_local
		je	.isLabel
		call	bnf_label_global
		jne	.notLabel
		mov	ebx,instr_list		; is instruction?
		mov	ecx,instr_list.size
		call	array_search2
		je	.isKey
		mov	ebx,reg_list		; is register?
		mov	ecx,reg_list.size
		call	array_search2
		jne	.isLabel
	.isKey: mov	esi,edi
		sete	al
		test	al,al
		ret
      .isLabel: mov	al,byte[esi]		; check end condition
		cmp	al,'>'
		je	@f
		cmp	al,C_RETURN
		je	@f
		cmp	al,C_NEWLINE
		je	@f
		call	bnf_is_space
 .ok: .notLabel:;cmp	 byte[esi],0
		; there is a error here when a session is empty (ex. @code)
		ret
; <label> = <label_global> <label_local>? | <label_local> | <label_ref> | <addr_symbol>
; change (ecx, ebx, edi, edx)
; return (ZF) 1 = is label


bnf_label_op:	call	bnf_label_ref
		je	.yes
		call	bnf_addr_symbol
		je	.yes
		call	bnf_constant_op
		je	.yes
		call	bnf_label_local
		je	.yes
		call	bnf_label_global
		jne	.notLabel
		mov	ebx,instr_list
		mov	ecx,instr_list.size
		call	array_search2
		je	.isKey
	    @@: mov	ebx,reg_list		; is register?
		mov	ecx,reg_list.size
		call	array_search2
		je	.isKey
		cmp	byte[esi],'.'
		jne	.ok
		call	bnf_label_local
		ret
	.isKey: mov	esi,edi
		sete	al
		test	al,al
		ret
	   .ok: xor	eax,eax
.yes:.notLabel: ret
; <label_op> = <label_global> <label_local>? | <label_local> | <label_ref> | <addr_symbol>
; change (ebx, edi)
; return (ZF) 1 = is label


bnf_label_local:mov	edi,esi
		lodsb
		cmp	al,'.'
		jne	.no
		call	bnf_name
		jne	.no
		ret
	   .no: mov	esi,edi
		ret
; <label_local> = .<name>
; change (ebx, edi)
; return (ZF) 1 = is local label


bnf_addr_symbol:mov	edi,esi
		lodsb
		cmp	al,'$'
		jne	.no
		lodsb
		cmp	al,'$'
		jne	@f
		lodsb
		cmp	al,'$'
		je	.no
	    @@: dec	esi
		call	bnf_let_or_num
		sete	al
		je	.no
	  .yes: xor	eax,eax
		ret
	   .no: mov	esi,edi
		test	al,al
		ret
;<addr_symbol> = $ | $$
; change (edi)
; return (ZF) 1 = is address symbol


bnf_label_ref:	mov	edi,esi
		lodsb
		cmp	al,'>'
		je	.ok
		cmp	al,'<'
		jne	.no
	   .ok: mov	ah,al
	    @@: lodsb
		cmp	al,ah
		je	@b
		xor	al,ah
		cmp	al,10b
		je	.no
		dec	esi
	  .yes: xor	eax,eax
		ret
	   .no: mov	esi,edi
		test	al,al
		ret
; <label_ref> = >+ | <+
; change (edi)
; return (ZF) 1 = is reference label
bnf_label_ref_once:
		mov	edi,esi
		lodsb
		cmp	al,'>'
		jne	.no
		mov	al,byte[esi]
		cmp	al,'>'
		je	.no
		cmp	al,'<'
		je	.no
	  .yes: xor	eax,eax
		ret
	   .no: mov	esi,edi
		test	al,al
		ret
; <label_ref_once> = >
; change (edi)
; return (ZF) 1 = is once reference label


bnf_string:	;mov	 edi,esi
		lodsb
		cmp	al,"'"
		je	.get
		cmp	al,'"'
		jne	.no
	  .get: mov	ah,al
		call	bnf_anything
		cmp	ah,al
		jne	.no
	  .yes: ret
	   .no: ;mov	 esi,edi
		dec esi
		ret
; <string> = '<anything>' | "<anything>"
; change (edi)
; return ( ZF ) 1 = is string


bnf_anything_l: mov	ah,C_NEWLINE
bnf_anything:	;mov	 edi,esi
	    @@: lodsb
		test	al,al
		jz	.done
		cmp	al,C_NEWLINE
		je	.done
		cmp	al,ah
		jne	@b
		ret
	 .done: ;mov	 esi,edi
		dec esi
		ret
; <anything>
; change (edi)
; in ( char_stop_condition ah )
bnf_anything_m: mov	edi,esi
	    @@: lodsb
		test	al,al
		jz	.done
		cmp	al,C_NEWLINE
		je	.account
		cmp	al,ah
		jne	@b
		ret
	 .done: mov	esi,edi
		ret
      .account: inc	[line_number]
		jmp	@b
; <anything_multiline>
; change (edi)
; in ( char_stop_condition ah )


bnf_number:	call	bnf_decimal
		je	.yes
		call	bnf_binary
		je	.yes
		call	bnf_hexadecimal
	  .yes: ret
; <number> = <decimal> | <binary> | <hexadecimal>
; change (ebx)
; return (ZF) 1 = is number


bnf_hexadecimal:mov	edi,esi
		lodsb
		cmp	al,'0'
		jne	.no
		lodsb
		cmp	al,'x'
		jne	.no
		mov	ebx,esi
	    @@: lodsb
		cmp	al,'0'
		jb	@f
		cmp	al,'9'
		jbe	@b
		cmp	al,'A'
		jb	@f
		cmp	al,'F'
		jbe	@b
	    @@: dec	esi
		cmp	ebx,esi
		je	.no
		call	bnf_let_or_num
		sete	al
		je	.no
		xor	eax,eax
		ret
	   .no: mov	esi,edi
		test	al,al
		ret
; <hexadecimal> = 0x[0-9A-F]+
; change (ebx, edi)
; return (ZF) 1 = is hexadecimal


bnf_decimal:	mov	edi,esi
		lodsb
		cmp	al,'0'
		jb	.no
		cmp	al,'9'
		ja	.no
	    @@: lodsb
		cmp	al,'0'
		jb	@f
		cmp	al,'9'
		jbe	@b
	    @@: dec	esi
		call	bnf_let_or_num
		sete	al
		je	.no
		xor	eax,eax
		ret
	   .no: mov	esi,edi
		test	al,al
		ret
; <decimal> = [0-9]+
; change (edi)
; return (ZF) 1 = is decimal


bnf_binary:	mov	edi,esi
		lodsb
		cmp	al,'0'
		jb	.no
		cmp	al,'1'
		ja	.no
	    @@: lodsb
		cmp	al,'0'
		je	@b
		cmp	al,'1'
		je	@b
		cmp	al,'b'
		jne	.no
		call	bnf_let_or_num
		sete	al
		je	.no
		xor	eax,eax
		ret
	   .no: mov	esi,edi
		test	al,al
		ret
; <binary> = [0-1]+b
; change (edi)
; return (ZF) 1 = is binary


bnf_let_or_num: lodsb
		cmp	al,'0'
		jb	.no
		cmp	al,'9'
		jbe	.yes
		cmp	al,'A'
		jb	.no
		cmp	al,'Z'
		jbe	.yes
		cmp	al,'a'
		jb	.no
		cmp	al,'z'
		jg	.no
	  .yes: xor	eax,eax
		ret
	   .no: dec	esi
		ret
; solve [0-9A-Za-z]
; return ( ZF ) 1 = is letter or number


bnf_op_override:lodsb
		cmp	al,'b'
		je	.yes
		cmp	al,'w'
		je	.yes
		cmp	al,'d'
		je	.yes
		dec	esi
	  .yes: ret
; <op_override> = b | w | d
; return (ZF) 1 = is operator override


bnf_access_flag:call	bnf_skipspace
		lodsb
		cmp	al,'r'
		je	.r_ok
		dec	esi
	 .r_ok: lodsb
		cmp	al,'w'
		je	.w_ok
		dec	esi
	 .w_ok: lodsb
		cmp	al,'e'
		je	.e_ok
		dec	esi
	 .e_ok: ret
; <access_flag> = r?w?e?
; return (ZF) 1 = is access flag


bnf_skipspace:	lodsb
		cmp	al,C_TAB
		je	bnf_skipspace
		cmp	al,C_SPACE
		je	bnf_skipspace
		cmp	al,C_RETURN
		je	bnf_skipspace
		dec	esi
		ret
; <s> = ' ' | \t | \r
bnf_skipspace_m:lodsb
		cmp	al,C_TAB
		je	bnf_skipspace_m
		cmp	al,C_SPACE
		je	bnf_skipspace_m
		cmp	al,C_RETURN
		je	bnf_skipspace_m
		cmp	al,C_NEWLINE
		je	.account
		dec	esi
		ret
      .account: inc	[line_number]
		jmp	bnf_skipspace_m
; <s> = ' ' | \t | \r | \n


bnf_is_space:	lodsb
		cmp	al,C_TAB
		je	.yes
		cmp	al,C_SPACE
		je	.yes
		;cmp	 al,C_RETURN
		;je	 .yes
		dec	esi
	  .yes: ret
; <s> = ' ' | \t | \r


bnf_endline:	call	 bnf_skipspace
		lodsb
		cmp	al,C_NEWLINE
		jne	.noCount
		inc	[line_number]
		xor	eax,eax
		ret
      .noCount: dec	esi
		ret
; <endline>  = \n
; return (ZF) 1 = is new line


array_search:
		push	esi
		push	edi
		mov	edx,keyword
	  .for: mov	esi,edx
		mov	edi,[ebx+ecx*4]  ; INSTS.MOV
		mov	edi,[edi+4]	 ; INSTS.MOV.str
	    @@: mov	al,[esi]
		cmp	[edi],al
		jne	.neq
		inc	esi
		inc	edi
		test	al,al
		jnz	@b
		; <here i found a item!>
		mov	ebx,[ebx+ecx*4]
		mov	ebx,[ebx]
		;xor	 eax,eax
		jmp	.done
	  .neq: dec	ecx
		jns	.for
	 .done: pop	edi
		pop	esi
		ret
; perform a search in an array
; in ( keyword edx, list ebx, list_size ecx )
; change ( ebx, edx, ecx )
; return (ZF) 1 = found; (EBX) function to bnf_operand_XXXXX


array_search2:
	push	esi
	push	edi
	mov	edx,keyword
  .for: mov	esi,edx
	mov	edi,[ebx+ecx*4]
    @@: mov	al,[esi]
	cmp	[edi],al
	jne	.neq
	inc	esi
	inc	edi
	test	al,al
	jnz	@b
	; <here i found a item!>
	;xor	 eax,eax
	jmp	.done
  .neq: dec	ecx
	jns	.for
 .done: pop	edi
	pop	esi
	ret
; perform a search in a string array
; in ( keyword edx, list ebx, list_size ecx )
; change ( ecx, edx )
; return (ZF) 1 = found


expected:
	; Prints a expected character msg and exit
	; input(eax character)
	cinvoke printf,msg_exp,eax,[line_number]
	jmp	_exit
	ret
	msg_exp db "'%c' expected! [%d]",C_NEWLINE,0


invalid:
	; Prints an invalid msg and exit
	; input(eax string pointer)
	cinvoke printf,msg_inv,eax,[line_number]
	jmp	_exit
	ret
	msg_inv db 'Invalid %s [%d]',C_NEWLINE,0

error:
	; Prints an error msg and exit
	; input(eax string pointer)
	cinvoke printf,msg_err,eax,[line_number]
	jmp	_exit
	ret
	msg_err db 'Error: %s [%d]',C_NEWLINE,0

msg:
	; Prints a msg
	; input(ebx string pointer)
	cinvoke printf,msg_msg,ebx,[line_number]
	ret
	msg_msg db '%s [%d]',C_NEWLINE,0



; +-----------------------------------------------------------------------------



section '.data' code readable writable

	C_TAB	  = 0x09	; \t
	C_NEWLINE = 0x0A	; \n
	C_RETURN  = 0x0D	; \r
	C_SPACE   = 0x20	; ' '
	C_EOF	  = 0

	app_path db 256 dup 0
	src_path db 256 dup 0
	keyword  db 256 dup 0

	src_ptr dd ?

	dst_ptr dd ?
	dst_buff_size dd 512
	dst_total_bytes_to_write dd 0


	useless dd ?

	line_number dd 1

    ; Strings arrays

    instr_list dd instr_str.adc
	       dd instr_str.add
	       dd instr_str.and
	       dd instr_str.dec
	       dd instr_str.inc
	       dd instr_str.int
	       dd instr_str.mov
	       dd instr_str.or
	       dd instr_str.pop
	       dd instr_str.push
	       dd instr_str.sub
	       dd instr_str.test
	       dd instr_str.xor
	       dd instr_str.db
	       dd instr_str.dw
	       dd instr_str.dd
	       dd instr_str.rb
	       dd instr_str.rw
	       dd instr_str.rd
	 .size = ($-instr_list) shr 2 - 1

    ;header_list dd header_str.pe
    ;		 dd header_str.pec
    ;		 dd header_str.dll
    ;		 dd header_str.com
    ;		 dd header_str.bin
    ;	  .size = ($-header_list) shr 2 - 1
    ;
    ;session_list dd session_str.code
    ;		  dd session_str.data
    ;		  dd session_str.udata
    ;		  dd session_str.idata
    ;	  .size = ($-session_list) shr 2 - 1

    reg_list dd regs32_str.eax
	     dd regs32_str.ebx
	     dd regs32_str.ecx
	     dd regs32_str.edx
	     dd regs32_str.esi
	     dd regs32_str.edi
	     dd regs32_str.esp
	     dd regs32_str.ebp
	     dd regs16_str.ax	   ;16
	     dd regs16_str.bx
	     dd regs16_str.cx
	     dd regs16_str.dx
	     dd regs16_str.si
	     dd regs16_str.di
	     dd regs16_str.sp
	     dd regs16_str.bp
	     dd regs08_str.ah	   ;08
	     dd regs08_str.al
	     dd regs08_str.bh
	     dd regs08_str.bl
	     dd regs08_str.ch
	     dd regs08_str.cl
	     dd regs08_str.dh
	     dd regs08_str.dl
	 .size = ($-reg_list) shr 2 - 1

    ; Structures arrays

    HEADERS:
	    dd HEADER_PE
	    dd HEADER_PEC
	    dd HEADER_DLL
	    dd HEADER_COM
	    dd HEADER_BIN
	.size = ($-HEADERS) shr 2 - 1

    SESSIONS:
	    dd SESSION_CODE
	    dd SESSION_DATA
	    dd SESSION_UDATA
	    ;dd SESSION_IDATA
	.size = ($-SESSIONS) shr 2 - 1


    DIRECTIVES:
	    dd DIRECTIVE_16
	    dd DIRECTIVE_32
	    dd DIRECTIVE_ORG
	    dd DIRECTIVE_ALIGN
	    dd DIRECTIVE_DEBUG
	    dd DIRECTIVE_RELEASE
	    dd DIRECTIVE_INCLUDE
	    dd DIRECTIVE_SIZE
	.size = ($-DIRECTIVES) shr 2 - 1

    INSTS:
	    dd INSTR_ADC
	    dd INSTR_ADD
	    dd INSTR_AND
	    dd INSTR_DEC
	    dd INSTR_INC
	    dd INSTR_INT
	    dd INSTR_MOV
	    dd INSTR_OR
	    dd INSTR_POP
	    dd INSTR_PUSH
	    dd INSTR_SUB
	    dd INSTR_TEST
	    dd INSTR_XOR
	    dd INSTR_DB
	    dd INSTR_DW
	    dd INSTR_DD
	    dd INSTR_RB
	    dd INSTR_RW
	    dd INSTR_RD
	.size = ($-INSTS) shr 2 - 1

    ; Virtual Methods Tables

    VMT_OPERAND_DST_SRC:
		dd bnf_operand_dst_src
    VMT_OPERAND_DST:
		dd bnf_operand_dst
    VMT_OPERAND_SRC:
		dd bnf_operand_src
    VMT_OPERAND_DEF_DATA:
		dd bnf_operand_def_data
    VMT_OPERAND_DEF_RDATA:
		dd bnf_operand_def_rdata
    VMT_OPERAND_NONE:
		dd bnf_operand_none
    VMT_OPERAND_IMM:
		dd bnf_operand_imm
    VMT_OPERAND_BODY:
		dd bnf_body
    VMT_OPERAND_BLOCK:
		dd bnf_block
    VMT_OPERAND_STR:
		dd bnf_operand_str
    VMT_OPERAND_DIR_SIZE:
		dd bnf_operand_dirsize
    VMT_OPERAND_PE:
		dd bnf_pe
    VMT_OPERAND_PE_SESSION:
		dd bnf_pe_session

    ; instructions

    INSTR_ADC:
	.type dd VMT_OPERAND_DST_SRC
	.str  dd instr_str.adc
    INSTR_ADD:
	.type dd VMT_OPERAND_DST_SRC
	.str  dd instr_str.add
    INSTR_AND:
	.type dd VMT_OPERAND_DST_SRC
	.str  dd instr_str.and
    INSTR_DEC:
	.type dd VMT_OPERAND_DST
	.str  dd instr_str.dec
    INSTR_INC:
	.type dd VMT_OPERAND_DST
	.str  dd instr_str.inc
    INSTR_INT:
	.type dd VMT_OPERAND_IMM
	.str  dd instr_str.int
    INSTR_MOV:
	.type dd VMT_OPERAND_DST_SRC
	.str  dd instr_str.mov
    INSTR_OR:
	.type dd VMT_OPERAND_DST_SRC
	.str  dd instr_str.or
    INSTR_POP:
	.type dd VMT_OPERAND_DST
	.str  dd instr_str.pop
    INSTR_PUSH:
	.type dd VMT_OPERAND_DST
	.str  dd instr_str.push
    INSTR_SUB:
	.type dd VMT_OPERAND_DST_SRC
	.str  dd instr_str.sub
    INSTR_TEST:
	.type dd VMT_OPERAND_DST_SRC
	.str  dd instr_str.test
    INSTR_XOR:
	.type dd VMT_OPERAND_DST_SRC
	.str  dd instr_str.xor
    INSTR_DB:
	.type dd VMT_OPERAND_DEF_DATA
	.str  dd instr_str.db
    INSTR_DW:
	.type dd VMT_OPERAND_DEF_DATA
	.str  dd instr_str.dw
    INSTR_DD:
	.type dd VMT_OPERAND_DEF_DATA
	.str  dd instr_str.dd
    INSTR_RB:
	.type dd VMT_OPERAND_DEF_RDATA
	.str  dd instr_str.rb
    INSTR_RW:
	.type dd VMT_OPERAND_DEF_RDATA
	.str  dd instr_str.rw
    INSTR_RD:
	.type dd VMT_OPERAND_DEF_RDATA
	.str  dd instr_str.rd

    ; directives

    DIRECTIVE_16:
	.type dd VMT_OPERAND_NONE
	.str  dd directive_str.16
    DIRECTIVE_32:
	.type dd VMT_OPERAND_NONE
	.str  dd directive_str.32
    DIRECTIVE_ORG:
	.type dd VMT_OPERAND_IMM
	.str  dd directive_str.org
    DIRECTIVE_ALIGN:
	.type dd VMT_OPERAND_IMM
	.str  dd directive_str.alg
    DIRECTIVE_DEBUG:
	.type dd VMT_OPERAND_BLOCK
	.str  dd directive_str.dbg
    DIRECTIVE_RELEASE:
	.type dd VMT_OPERAND_BLOCK
	.str  dd directive_str.rls
    DIRECTIVE_INCLUDE:
	.type dd VMT_OPERAND_STR
	.str  dd directive_str.inc
    DIRECTIVE_SIZE:
	.type dd VMT_OPERAND_DIR_SIZE
	.str  dd directive_str.siz

    ; headers

    HEADER_PE:
	.type dd VMT_OPERAND_PE
	.str  dd header_str.pe
    HEADER_PEC:
	.type dd VMT_OPERAND_PE
	.str  dd header_str.pec
    HEADER_DLL:
	.type dd VMT_OPERAND_PE
	.str  dd header_str.dll
    HEADER_COM:
	.type dd VMT_OPERAND_BODY
	.str  dd header_str.com
    HEADER_BIN:
	.type dd VMT_OPERAND_BODY
	.str  dd header_str.bin

    ; sessions

    SESSION_CODE:
	.type dd VMT_OPERAND_PE_SESSION
	.str  dd session_str.scode
    SESSION_DATA:
	.type dd VMT_OPERAND_PE_SESSION
	.str  dd session_str.sdata
    SESSION_UDATA:
	.type dd VMT_OPERAND_PE_SESSION
	.str  dd session_str.sudata
    SESSION_IDATA:
	.type dd VMT_OPERAND_NONE
	.str  dd session_str.sidata

    ; strings

    instr_str:
	.adc db 'adc',0
	.add db 'add',0
	.and db 'and',0
	.dec db 'dec',0
	.inc db 'inc',0
	.int db 'int',0
	.mov db 'mov',0
	 .or db 'or',0
	.pop db 'pop',0
       .push db 'push',0
	.sub db 'sub',0
       .test db 'test',0
	.xor db 'xor',0
	 .db db 'db',0
	 .dw db 'dw',0
	 .dd db 'dd',0
	 .rb db 'rb',0
	 .rw db 'rw',0
	 .rd db 'rd',0

    regs32_str:
	.eax db 'eax',0
	.ebx db 'ebx',0
	.ecx db 'ecx',0
	.edx db 'edx',0
	.esi db 'esi',0
	.edi db 'edi',0
	.esp db 'esp',0
	.ebp db 'ebp',0
    regs16_str:
	.ax db 'ax',0
	.bx db 'bx',0
	.cx db 'cx',0
	.dx db 'dx',0
	.si db 'si',0
	.di db 'di',0
	.sp db 'sp',0
	.bp db 'bp',0
    regs08_str:
	.ah db 'ah',0
	.al db 'al',0
	.bh db 'bh',0
	.bl db 'bl',0
	.ch db 'ch',0
	.cl db 'cl',0
	.dh db 'dh',0
	.dl db 'dl',0

    header_str:
	.pe db 'PE',0
       .pec db 'PEC',0
       .dll db 'DLL',0
       .com db 'COM',0
       .bin db 'BIN',0

    session_str:
	.scode db 'code',0
	.sdata db 'data',0
       .sudata db 'udata',0
       .sidata db 'idata',0

    directive_str:
	.16  db '16',0
	.32  db '32',0
	.org db 'org',0
	.alg db 'align',0
	.dbg db 'debug',0
	.rls db 'release',0
	.inc db 'include',0
	.siz db 'size',0

    str_line   db 'line',0
    str_number db 'number',0


section '.idata' import data readable

	library kernel32,'kernel32.dll',msvcrt,'MSVCRT.DLL',\
		user32,'user32.dll',shell32,'shell32.dll'
	import msvcrt,printf,'printf',scanf,'scanf',exit,'exit',system,'system'
